#include <QGLWidget>

#include "vxgraphicsview.h"
#include "vxruller.h"
#include "vxtools.h"
#include "vxdockselector.h"
#include "vx.h"
#include "vxanchor.h"
#include "vxcommandscontroller.h"
#include "vxscaletrigger.h"
#include "vxmousetransmitter.h"

/*
 *
 *
 * VxProxyWidget
 *
 *
 */


VxProxyWidget::VxProxyWidget(VxGraphicsView * view, QGraphicsItem * parent) :
			QGraphicsProxyWidget(parent), _view(view), _pressed(false)
{


	connect(_view, SIGNAL(beforeViewPaint()), this, SLOT(_beforeViewPaint()));
	connect(VxMouseTransmitter::instance(), SIGNAL(mouseReleased(QMouseEvent*)),
										this, SLOT(_cancelPressed()));
	_viewp = QPoint(0,0);

	_animation = new QPropertyAnimation(this, "viewPos", this);
	_animation->setEasingCurve(QEasingCurve::OutQuart);

	connect(_animation, SIGNAL(valueChanged(QVariant)), this, SLOT(_valueChanged(QVariant)));

}

void VxProxyWidget::initFloating()
{
	connect(VxMouseTransmitter::instance(), SIGNAL(mouseMomentum(QPoint,qreal)),
			this, SLOT(_mouseMomentum(QPoint, qreal)));
}

VxProxyWidget::~VxProxyWidget()
{
	delete _animation;
}


void VxProxyWidget::setViewPos(int x, int y)
{
	 setViewPos(QPoint(x, y));
}


void VxProxyWidget::setViewPos(QPoint p)
{
	_viewp = validatePos(p);

	QPointF sp = _view->mapToScene(_viewp);

	QPointF ps = pos();

	if (ps.x() != sp.x() || ps.y() != sp.y()){
		setPos(sp);
	}

	QPoint deltap = _viewp - p;
	if (deltap.manhattanLength() > Vx::BreakdownMomentum){
		emit breakdownEffort(deltap);
	}

	emit movement(deltap.x(), deltap.y());

}


QPoint VxProxyWidget::getViewPos()
{
	return _viewp;
}


void VxProxyWidget::_valueChanged(QVariant value)
{
	if (widget() == NULL){
		return;
	}


	bool outv = _animation->property("_outOfView").toBool();

	if (outv){
		return;
	}

	int time = _animation->property("_time").toInt();
	int crtm = _animation->currentTime();
	_animation->setProperty("_time", crtm);
	if (time < 0){
		return;
	}
	int dltt = crtm - time;

	QPointF p = value.toPointF();
	QPointF oldp = _animation->property("_point").toPointF();
	_animation->setProperty("_point", p);

	if (_isValidatePos(p)){
		return;
	}

	QPointF dltp = p - oldp;
	qreal momentum = dltp.manhattanLength()/dltt;

	if (momentum < Vx::BreakdownMomentum){
		return;
	}

	_animation->setProperty("_outOfView", true);

	emit breakdownMomentum(momentum);

}


bool VxProxyWidget::_isValidatePos(QPointF p)
{
	if (p.x() < 0 || p.y() < 0 ||
		p.x() + widget()->width() > _view->viewport()->width() ||
		p.y() + widget()->height() > _view->viewport()->height()){
		return false;
	}
	return true;
}



QPoint VxProxyWidget::validatePos(QPoint p)
{
	QPoint resp = p;
	if (widget() == NULL){
		return resp;
	}
	if (p.x() + widget()->width() > _view->viewport()->width()){
		resp.setX(_view->viewport()->width() - widget()->width() - 0);
	}
	if (resp.x() < 0){
		resp.setX(0);
	}
	if (p.y() + widget()->height() > _view->viewport()->height()){
		resp.setY(_view->viewport()->height() - widget()->height() - 0);
	}
	if (resp.y() < 0){
		resp.setY(0);
	}

	return resp;
}



void VxProxyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event){
	QGraphicsProxyWidget::mousePressEvent(event);
	if (event->isAccepted()){
		return;
	}

	if (widget() == NULL){
		QGraphicsProxyWidget::mousePressEvent(event);
		return;
	}
	_pressed = true;
	_animation->stop();

	connect(VxMouseTransmitter::instance(), SIGNAL(mouseMomentum(QPoint,qreal)),
			this, SLOT(_mouseMomentum(QPoint, qreal)));

	event->accept();
}


void VxProxyWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event){

	if (!_pressed){
		QGraphicsProxyWidget::mouseMoveEvent(event);
		return;
	}

	QPointF dp = event->pos() - event->lastPos();

	dp = dp / _view->matrix().m11();

	QPoint vp = _view->mapFromScene(pos() + dp);

	setViewPos(vp);


	qApp->processEvents();

	event->accept();
}


void VxProxyWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
	_cancelPressed();

	QGraphicsProxyWidget::mouseReleaseEvent(event);

}


void VxProxyWidget::_cancelPressed()
{
	_pressed = false;
	disconnect(VxMouseTransmitter::instance(), SIGNAL(mouseMomentum(QPoint,qreal)),
			this, SLOT(_mouseMomentum(QPoint, qreal)));
}

void VxProxyWidget::_beforeViewPaint()
{

	_viewp = validatePos(_viewp);

	QMatrix m = this->matrix();

	m.reset();

	qreal s = 1/_view->matrix().m11();
	m.scale(s, s);

	QPointF vp = _view->mapToScene(_viewp);

	this->setMatrix(m);

	this->setPos(vp);

}


void VxProxyWidget::_mouseMomentum(QPoint delta, qreal momentum)
{
	if (!_pressed){
		return;
	}
	_animation->setStartValue(_viewp);
	_animation->setEndValue(_viewp + delta*momentum);
	_animation->setDuration(Vx::HandMoveDelay);
	_animation->start();
	_animation->setProperty("_time", -1);
	_animation->setProperty("_outOfView", false);

}


void VxProxyWidget::cancelAnimation()
{
	if (_animation->state() == QAbstractAnimation::Running){
		_animation->stop();
	}
}


/*
 *
 *
 * VxGraphicsView
 *
 *
 */

VxGraphicsView::VxGraphicsView(QGraphicsScene *scene, QWidget *parent) :
		QGraphicsView(scene, parent), _mpress(false)
{
	_init();
}


VxGraphicsView::~VxGraphicsView()
{
}


void VxGraphicsView::_init()
{
	_createControls();
}



void VxGraphicsView::paintEvent(QPaintEvent *event)
{
	emit beforeViewPaint();
	QGraphicsView::paintEvent(event);
}



void VxGraphicsView::resizeEvent(QResizeEvent *event)
{
	QGraphicsView::resizeEvent(event);
	viewport()->setMask(QRegion(0,0, size().width(), size().height()));
}



void VxGraphicsView::_createControls()
{

	//setViewport(new QGLWidget());

	_zoomController = new VxZoomController(this);
	_handController = new VxHandController(this);

	_rullers = VxRullersProxyWidget::createInstance(this);

}






